一、OutOfMemoryError 和 StackOverflowError
1️⃣堆区域用来存放 Class 的实例(即对象),对象需要存储的内容主要是非静态属性。每次用 new 创建一个对象实例后,对象实例存储在堆区域中,这部分空间也被 JVM 的垃圾回收机制管理。
【Java 堆内存溢出】java.lang.OutOfMemoryError:java heap space
最常见,一般由于内存泄露或者堆的大小设置不当引起。原因是 JVM 创建的对象太多,在进行垃圾回收之间,虚拟机分配的到堆内存空间已经用满了,与 Heap space 有关。解决这类问题有两种思路:
- 对于内存泄露,可以通过内存监控软件查找程序中的泄露代码。检查程序,看是否有死循环或不必要地重复创建大量对象。找到原因后,修改程序和算法。
- 增加 JVM 中 Xms(初始堆大小)和 Xmx(最大堆大小)参数的大小。如:
set JAVA_OPTS= -Xms256m -Xmx1024m
2️⃣Java 栈跟大多数编程语言包括汇编语言的栈功能相似,主要基本类型变量以及方法的输入输出参数。
【Java 栈内存溢出】java.lang.StackOverflowError
也比较常见。Java 栈溢出,一般是由于程序中存在死循环或者深度递归调用造成的,栈大小设置太小也会出现此种溢出。可以通过虚拟机参数-Xss来设置栈的大小。
二、Java 运行时数据区(Runtime Data Area)
Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域,即运行时数据区(Runtime Data Area):
- 【程序计数器】《Java虚拟机规范》中唯 一一个没有规定任何OutOfMemoryError情况的区域。
- 【Java虚拟机栈】《Java虚拟机规范》对该区域规定了两类异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError;如果Java虚拟机栈容量可以动态扩展,当栈扩展时无法申请到足够的内存会抛出OutOfMemoryError。
- 【本地方法栈】与虚拟机栈一样,也会在栈深度溢出或者栈扩展失败时分别抛出StackOverflowError和OutOfMemoryError。
- 【Java堆】既可以被实现成固定大小的,也可以是可扩展的,不过当前主流的Java虚拟机都是按照可扩展来实现的
通过参数-Xmx和-Xms设定
。如果Java堆中没有内存完成实例分配,并且堆也无法再扩展时,Java虚拟机将会抛出OutOfMemoryError。 - 【方法区】《Java虚拟机规范》规定,如果方法区无法满足新的内存分配需求时,将抛出OutOfMemoryError。
三、常见场景
1️⃣静态集合类声明为静态static的HashMap、Vector 等集合。通俗来讲A中有B,当前只把B设置为空,A没有设置为空,回收时B无法被回收,因为被A引用。
2️⃣物理连接:DataSource.getConnection()
建立链接,必须通过close()关闭链接。
3️⃣内部类和外部模块等的引用
GC只会回收没有被引用或者根集不可到达的对象(取决于 GC 算法),内部类在生命周期内始终持有外部类的对象的引用,造成外部类的对象始终不满足 GC 的回收条件,反映在内存上就是内存泄露。常见解决方案:
- 将内部类定义为static
- 用static的变量引用匿名内部类的实例或将匿名内部类的实例化操作放到外部类的静态方法中
4️⃣【OutOfMemoryError:unable to create new native thread】Executors 返回的线程池对象的弊端如下:
- FixedThreadPool 和 SingleThreadPool:
允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。 - CachedThreadPool 和 ScheduledThreadPool:
允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。
四、分析定位
1️⃣在未明确找到问题原因前,先添配置 JVM 启动参数,监控复原 OOM 场景自动dump:-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${目录}
2️⃣
- 获取内存的堆信息
jmap -dump:format=b,file=mem.dat pid
- 使用内存映像分析工具(如Eclipse Memory Analyzer)对 dump 出来的堆转存快照进行分析,重点是确认内存中的对象是否是必要的,先分清是因为内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)。
- 看分析图,查找对应问题,分析内存占用情况。例如:localstore 存储问题分析,大对象。